#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
AI营销方案生成系统 - 数据验证模块
功能：提供各种数据验证函数
作者：AI营销系统开发团队
创建时间：2024
"""

from typing import Dict, Any, List, Optional, Union
import re
from datetime import datetime
from bson import ObjectId


class ValidationError(Exception):
    """
    验证错误异常类
    """
    def __init__(self, message: str, field: str = None):
        self.message = message
        self.field = field
        super().__init__(self.message)


class BaseValidator:
    """
    基础验证器类
    """
    
    @staticmethod
    def validate_required(value: Any, field_name: str) -> None:
        """
        验证必填字段
        
        Args:
            value: 字段值
            field_name: 字段名称
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        if value is None or (isinstance(value, str) and not value.strip()):
            raise ValidationError(f"{field_name}不能为空", field_name)
    
    @staticmethod
    def validate_string_length(
        value: str, 
        field_name: str, 
        min_length: int = None, 
        max_length: int = None
    ) -> None:
        """
        验证字符串长度
        
        Args:
            value: 字符串值
            field_name: 字段名称
            min_length: 最小长度
            max_length: 最大长度
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        if not isinstance(value, str):
            raise ValidationError(f"{field_name}必须是字符串类型", field_name)
        
        length = len(value.strip())
        
        if min_length is not None and length < min_length:
            raise ValidationError(
                f"{field_name}长度不能少于{min_length}个字符", 
                field_name
            )
        
        if max_length is not None and length > max_length:
            raise ValidationError(
                f"{field_name}长度不能超过{max_length}个字符", 
                field_name
            )
    
    @staticmethod
    def validate_integer(
        value: Any, 
        field_name: str, 
        min_value: int = None, 
        max_value: int = None
    ) -> None:
        """
        验证整数
        
        Args:
            value: 整数值
            field_name: 字段名称
            min_value: 最小值
            max_value: 最大值
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        try:
            int_value = int(value)
        except (ValueError, TypeError):
            raise ValidationError(f"{field_name}必须是有效的整数", field_name)
        
        if min_value is not None and int_value < min_value:
            raise ValidationError(
                f"{field_name}不能小于{min_value}", 
                field_name
            )
        
        if max_value is not None and int_value > max_value:
            raise ValidationError(
                f"{field_name}不能大于{max_value}", 
                field_name
            )
    
    @staticmethod
    def validate_float(
        value: Any, 
        field_name: str, 
        min_value: float = None, 
        max_value: float = None
    ) -> None:
        """
        验证浮点数
        
        Args:
            value: 浮点数值
            field_name: 字段名称
            min_value: 最小值
            max_value: 最大值
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        try:
            float_value = float(value)
        except (ValueError, TypeError):
            raise ValidationError(f"{field_name}必须是有效的数字", field_name)
        
        if min_value is not None and float_value < min_value:
            raise ValidationError(
                f"{field_name}不能小于{min_value}", 
                field_name
            )
        
        if max_value is not None and float_value > max_value:
            raise ValidationError(
                f"{field_name}不能大于{max_value}", 
                field_name
            )
    
    @staticmethod
    def validate_email(email: str, field_name: str = 'email') -> None:
        """
        验证邮箱格式
        
        Args:
            email: 邮箱地址
            field_name: 字段名称
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        if not email or not isinstance(email, str):
            raise ValidationError(f"{field_name}不能为空", field_name)
        
        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        if not re.match(pattern, email.strip()):
            raise ValidationError(f"{field_name}格式不正确", field_name)
    
    @staticmethod
    def validate_phone(phone: str, field_name: str = 'phone') -> None:
        """
        验证手机号格式
        
        Args:
            phone: 手机号
            field_name: 字段名称
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        if not phone or not isinstance(phone, str):
            raise ValidationError(f"{field_name}不能为空", field_name)
        
        # 移除所有非数字字符
        phone_digits = re.sub(r'\D', '', phone)
        
        # 中国大陆手机号格式：11位数字，以1开头
        pattern = r'^1[3-9]\d{9}$'
        if not re.match(pattern, phone_digits):
            raise ValidationError(f"{field_name}格式不正确", field_name)
    
    @staticmethod
    def validate_object_id(obj_id: str, field_name: str) -> None:
        """
        验证ObjectId格式
        
        Args:
            obj_id: ObjectId字符串
            field_name: 字段名称
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        if not obj_id or not isinstance(obj_id, str):
            raise ValidationError(f"{field_name}不能为空", field_name)
        
        if not ObjectId.is_valid(obj_id):
            raise ValidationError(f"{field_name}格式不正确", field_name)
    
    @staticmethod
    def validate_choice(
        value: Any, 
        choices: List[Any], 
        field_name: str
    ) -> None:
        """
        验证选择项
        
        Args:
            value: 选择值
            choices: 可选项列表
            field_name: 字段名称
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        if value not in choices:
            raise ValidationError(
                f"{field_name}必须是以下值之一: {', '.join(map(str, choices))}", 
                field_name
            )


class TemplateValidator(BaseValidator):
    """
    规则模板验证器
    """
    
    @classmethod
    def validate_create_template(cls, data: Dict[str, Any]) -> None:
        """
        验证创建模板数据
        
        Args:
            data: 模板数据
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        # 验证必填字段
        cls.validate_required(data.get('name'), 'name')
        cls.validate_required(data.get('content'), 'content')
        
        # 验证字段长度
        cls.validate_string_length(data['name'], 'name', min_length=1, max_length=100)
        cls.validate_string_length(data['content'], 'content', min_length=10, max_length=10000)
        
        # 验证可选字段
        if 'description' in data and data['description']:
            cls.validate_string_length(
                data['description'], 
                'description', 
                max_length=500
            )
        
        if 'category' in data and data['category']:
            cls.validate_string_length(
                data['category'], 
                'category', 
                max_length=50
            )
        
        if 'tags' in data and data['tags']:
            if not isinstance(data['tags'], list):
                raise ValidationError("tags必须是数组类型", 'tags')
            
            for i, tag in enumerate(data['tags']):
                if not isinstance(tag, str):
                    raise ValidationError(f"tags[{i}]必须是字符串类型", 'tags')
                cls.validate_string_length(tag, f'tags[{i}]', min_length=1, max_length=20)
    
    @classmethod
    def validate_update_template(cls, data: Dict[str, Any]) -> None:
        """
        验证更新模板数据
        
        Args:
            data: 模板数据
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        # 更新时字段都是可选的，但如果提供了就需要验证
        if 'name' in data:
            cls.validate_required(data['name'], 'name')
            cls.validate_string_length(data['name'], 'name', min_length=1, max_length=100)
        
        if 'content' in data:
            cls.validate_required(data['content'], 'content')
            cls.validate_string_length(data['content'], 'content', min_length=10, max_length=10000)
        
        if 'description' in data and data['description']:
            cls.validate_string_length(
                data['description'], 
                'description', 
                max_length=500
            )
        
        if 'category' in data and data['category']:
            cls.validate_string_length(
                data['category'], 
                'category', 
                max_length=50
            )
        
        if 'tags' in data and data['tags']:
            if not isinstance(data['tags'], list):
                raise ValidationError("tags必须是数组类型", 'tags')
            
            for i, tag in enumerate(data['tags']):
                if not isinstance(tag, str):
                    raise ValidationError(f"tags[{i}]必须是字符串类型", 'tags')
                cls.validate_string_length(tag, f'tags[{i}]', min_length=1, max_length=20)


class RequirementValidator(BaseValidator):
    """
    需求验证器
    """
    
    @classmethod
    def validate_submit_requirement(cls, data: Dict[str, Any]) -> None:
        """
        验证提交需求数据
        
        Args:
            data: 需求数据
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        # 验证必填字段
        cls.validate_required(data.get('template_id'), 'template_id')
        cls.validate_required(data.get('form_data'), 'form_data')
        
        # 验证模板ID格式
        cls.validate_object_id(data['template_id'], 'template_id')
        
        # 验证表单数据
        if not isinstance(data['form_data'], dict):
            raise ValidationError("form_data必须是对象类型", 'form_data')
        
        # 验证可选字段
        if 'contact_info' in data and data['contact_info']:
            cls._validate_contact_info(data['contact_info'])
    
    @classmethod
    def _validate_contact_info(cls, contact_info: Dict[str, Any]) -> None:
        """
        验证联系信息
        
        Args:
            contact_info: 联系信息
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        if not isinstance(contact_info, dict):
            raise ValidationError("contact_info必须是对象类型", 'contact_info')
        
        # 验证姓名
        if 'name' in contact_info and contact_info['name']:
            cls.validate_string_length(
                contact_info['name'], 
                'contact_info.name', 
                min_length=1, 
                max_length=50
            )
        
        # 验证邮箱
        if 'email' in contact_info and contact_info['email']:
            cls.validate_email(contact_info['email'], 'contact_info.email')
        
        # 验证手机号
        if 'phone' in contact_info and contact_info['phone']:
            cls.validate_phone(contact_info['phone'], 'contact_info.phone')
        
        # 验证公司
        if 'company' in contact_info and contact_info['company']:
            cls.validate_string_length(
                contact_info['company'], 
                'contact_info.company', 
                max_length=100
            )


class ChatValidator(BaseValidator):
    """
    聊天验证器
    """
    
    @classmethod
    def validate_create_session(cls, data: Dict[str, Any]) -> None:
        """
        验证创建会话数据
        
        Args:
            data: 会话数据
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        # 验证必填字段
        cls.validate_required(data.get('requirement_id'), 'requirement_id')
        
        # 验证需求ID格式
        cls.validate_object_id(data['requirement_id'], 'requirement_id')
        
        # 验证可选字段
        if 'session_name' in data and data['session_name']:
            cls.validate_string_length(
                data['session_name'], 
                'session_name', 
                min_length=1, 
                max_length=100
            )
    
    @classmethod
    def validate_generate_plan(cls, data: Dict[str, Any]) -> None:
        """
        验证生成方案数据
        
        Args:
            data: 生成数据
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        # 验证必填字段
        cls.validate_required(data.get('requirement_id'), 'requirement_id')
        cls.validate_required(data.get('session_id'), 'session_id')
        
        # 验证ID格式
        cls.validate_object_id(data['requirement_id'], 'requirement_id')
        cls.validate_object_id(data['session_id'], 'session_id')
        
        # 验证可选字段
        if 'user_message' in data and data['user_message']:
            cls.validate_string_length(
                data['user_message'], 
                'user_message', 
                min_length=1, 
                max_length=2000
            )
    
    @classmethod
    def validate_feedback(cls, data: Dict[str, Any]) -> None:
        """
        验证反馈数据
        
        Args:
            data: 反馈数据
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        # 验证必填字段
        cls.validate_required(data.get('session_id'), 'session_id')
        cls.validate_required(data.get('feedback_message'), 'feedback_message')
        
        # 验证会话ID格式
        cls.validate_object_id(data['session_id'], 'session_id')
        
        # 验证反馈消息
        cls.validate_string_length(
            data['feedback_message'], 
            'feedback_message', 
            min_length=1, 
            max_length=2000
        )
        
        # 验证可选字段
        if 'previous_response_id' in data and data['previous_response_id']:
            cls.validate_string_length(
                data['previous_response_id'], 
                'previous_response_id', 
                min_length=1, 
                max_length=100
            )


class PaginationValidator(BaseValidator):
    """
    分页验证器
    """
    
    @classmethod
    def validate_pagination_params(
        cls, 
        page: Any, 
        limit: Any
    ) -> tuple[int, int]:
        """
        验证分页参数
        
        Args:
            page: 页码
            limit: 每页数量
            
        Returns:
            tuple[int, int]: 验证后的页码和每页数量
            
        Raises:
            ValidationError: 验证失败时抛出
        """
        # 验证页码
        try:
            page_int = int(page) if page else 1
            if page_int < 1:
                raise ValidationError("页码必须大于0", 'page')
        except (ValueError, TypeError):
            raise ValidationError("页码必须是有效的整数", 'page')
        
        # 验证每页数量
        try:
            limit_int = int(limit) if limit else 20
            if limit_int < 1:
                raise ValidationError("每页数量必须大于0", 'limit')
            elif limit_int > 100:
                raise ValidationError("每页数量不能超过100", 'limit')
        except (ValueError, TypeError):
            raise ValidationError("每页数量必须是有效的整数", 'limit')
        
        return page_int, limit_int


def validate_required_fields(data: Dict[str, Any], required_fields: List[str]) -> None:
    """
    验证必填字段
    
    Args:
        data: 要验证的数据
        required_fields: 必填字段列表
        
    Raises:
        ValidationError: 验证失败时抛出
    """
    if not isinstance(data, dict):
        raise ValidationError("数据必须是对象类型")
    
    for field in required_fields:
        if field not in data or data[field] is None or data[field] == '':
            raise ValidationError(f"缺少必填字段: {field}", field)


def validate_json_data(data: Any, schema: Dict[str, Any]) -> None:
    """
    根据schema验证JSON数据
    
    Args:
        data: 要验证的数据
        schema: 验证schema
        
    Raises:
        ValidationError: 验证失败时抛出
    """
    # 这里可以集成更复杂的JSON Schema验证库
    # 目前提供基础实现
    
    if not isinstance(data, dict):
        raise ValidationError("数据必须是对象类型")
    
    # 验证必填字段
    required_fields = schema.get('required', [])
    for field in required_fields:
        if field not in data or data[field] is None:
            raise ValidationError(f"缺少必填字段: {field}", field)
    
    # 验证字段类型
    properties = schema.get('properties', {})
    for field, field_schema in properties.items():
        if field in data:
            field_type = field_schema.get('type')
            field_value = data[field]
            
            if field_type == 'string' and not isinstance(field_value, str):
                raise ValidationError(f"{field}必须是字符串类型", field)
            elif field_type == 'integer' and not isinstance(field_value, int):
                raise ValidationError(f"{field}必须是整数类型", field)
            elif field_type == 'number' and not isinstance(field_value, (int, float)):
                raise ValidationError(f"{field}必须是数字类型", field)
            elif field_type == 'boolean' and not isinstance(field_value, bool):
                raise ValidationError(f"{field}必须是布尔类型", field)
            elif field_type == 'array' and not isinstance(field_value, list):
                raise ValidationError(f"{field}必须是数组类型", field)
            elif field_type == 'object' and not isinstance(field_value, dict):
                raise ValidationError(f"{field}必须是对象类型", field)